const log4js      = require('../../data/log');
const logger      = log4js.getLogger('info');
const server      = require('../../sip/server');
const constants   = require('../../data/constants');
const fs          = require('fs');
const request     = require("request");
const settingModel= require('../../model/setting');
const ffmpeg        = require('fluent-ffmpeg');
const channelCtrl    = require('./channel');
const channelModel   = require('../../model/channel');
const mediaserverModel = require('../../model/mediaserver');
const httpUtils   = require('../../utils/httpUtils');

/**
 * 与 ZLMediaKit 交互
 */
let Media={};

/**
 * 记录已使用的端口号
 */
Media.ports={ };

/**
 * 没有首页
 * @param {*} req
 * @param {*} res
 */
Media.index = function (req, res){
    // 处理逻辑 ...
    res.send('NOT IMPLEMENTED: index');
}

/**
 * 读取目标媒体服务器配置信息
 * 传入参数：host port secret
 */
Media.getServerConfig = function(req,res){
    let url = `http://${req.query.host}:${req.query.port}/index/api/getServerConfig?secret=${req.query.secret}`;
    httpUtils.get(url, '').then(tmp => {
        if(tmp.code === 0){
            tmp.code = constants.httpCode.OK.code
            tmp.message = constants.httpCode.OK.message
        }else{
            tmp.code = constants.httpCode.ILLEGAL_TOKEN.code;
            tmp.message = constants.httpCode.ILLEGAL_TOKEN.message
        }
        res.send(tmp);
    })

}
/**
 * ZLMediaKit 找不到流的时候请求这个接口
 */
Media.onStreamNotFound=function(req,res){
    res.send({'code':0,'msg':'success'});
};
Media.onFlowReport=function(req,res){
    res.send({'code':0,'msg':'success'});
};

/**
 * ZLMediaKit 启动时调用这个接口
 */
Media.onServerStarted=function(req,res){
    let serverId = req.body['general.mediaServerId'];
    constants.mediaservers[serverId] = req.body;
    res.send({'code':0, 'msg':'success'});
};

/**
 * ZLMediaKit 流没人观看时调用这个接口
 */
Media.onStreamNoneReader = async function (req, res) {
    logger.info('onStreamNoneReader', req.body);
    /**
     {
    mediaServerId: '',
    app: 'rtp',
    schema: 'rtmp',
    stream: 'v_34020000001320000002_34020000001310000006',
    vhost: '__defaultVhost__'
    }
     */
    let stream = req.body.stream.split('_');

    await server.bye(stream[1], stream[2]);
    res.send({'code': 0, 'msg': 'success'});
};

/**
 * ZLMediaKit 播放节目时调用这个接口
 */
Media.onPlay=async function(req,res){
    let mediaServerId = req.body.mediaServerId;
    let stream_id = req.body.stream;

    if(!mediaServerId || !stream_id){
        res.send({'code':1, 'msg':'参数错误','param': req.body});
        return;
    }

    const array = stream_id.split('_');

    logger.info(`mediaServierId=${mediaServerId} stream_id=${stream_id} onPlay被触发，准备请求媒体服务器打开rtp端口`);

    // 获取一个port
    try {
        const rtpRet = await Media.openRtpServer({body: {stream_id: stream_id, media_server_id: mediaServerId}});
        const res1 = rtpRet.res;
        const media_ip = rtpRet.mediaIp;

        // 发invite请求
        let stream = stream_id.split('_');
        let sendPort;
        if (res1.code === -300) {

            // 流已经存在，去查找一下
            const rows = await Media.listRtpServer(mediaServerId);
            let port = 0;
            const rtpPorts = rows.data.find((item) => {
                return item.stream_id === stream_id
            });
            logger.info(`mediaServierId=${mediaServerId} stream_id=${stream_id} 请求媒体服务器打开rtp端口时反馈流已存在,返回值:`,
                res1,'mediaIp=', media_ip,'listRtpServer列表', rows);
            if (rtpPorts) {
                port = rtpPorts.port;
            }
            if (port > 0) {
                sendPort = port;
            } else {
                sendPort = null;
                res.send({'code': 1, 'msg': '向媒体服务器申请rtp端口失败'});
            }
        } else {
            logger.info(`mediaServierId=${mediaServerId} stream_id=${stream_id} 请求媒体服务器打开rtp端口，新流准备分新端口`, res1, media_ip);
            sendPort = res1.port;
        }
        if(sendPort){
            const ret = await server.invite(media_ip, stream[1], stream[2], sendPort);
            logger.info(`mediaServierId=${mediaServerId} stream_id=${stream_id} port=${sendPort} 发送invite信令 返回值：`, ret);
            if (ret) {
                res.send({'code': 0, 'msg': 'success'});
            } else {
                res.send({'code': 1, 'msg': '发送invite信令失败'});
            }
        }else{
            logger.error(`mediaServierId=${mediaServerId} stream_id=${stream_id} 发送invite信令时没获取到rtp端口`);
        }
    }catch (e){
        res.send({'code': 1, 'msg': `发生异常:${e}`});
    }
};

/**
 * 播放hls时鉴权，这里暂时全设置为允许观看
 */
Media.onHttpAccess=function(req,res){
    res.send({
        'code':0,
        'err':'',
        path:req.body.path,
        second:600,
        mediaServerId:req.body.mediaServerId
    });
};

/**
 *
 * @param {*} req $app,$regist,$schema,$stream,$vhost
 * @param {*} res
 */
Media.onStreamChanged = async function(req,res){
    let method = req.body.regist;
    // let serverId = req.body.mediaServerId;

    if(method && req.body.schema==='rtsp'){
        // 注册时顺便截图
        let stream = req.body.stream.split('_');

        let rtmp = await channelCtrl.calcMediaUrl(stream[1], stream[2], 'rtmp_snap');
        logger.info('截图',rtmp);

        Media.snap(rtmp, stream[1], stream[2]).then((ret)=>{

            channelModel.updateSnap(ret.toString(), stream[1], stream[2]).then(()=>{
                res.send({'code':0, 'msg':'success'});
            }).catch(()=>{
                res.send({'code':1, 'msg':'更新截图信息失败'});
            })

        }).catch((err) => {
            logger.error(err);
        });
    }else{
        res.send({'code': 0, 'msg': 'success'});
    }
};

Media.onPublish=function(req,res){
    res.send({'code': 0, 'msg': 'success'});
};

/**
 * 查询rtp列表
 * @param {*} req
 * @param {*} res
 */
Media.rtpList=function(req,res){
    let serverId = req.query.media_server_id;
    Media.listRtpServer(serverId).then((list) => {
        res.send(Object.assign(constants.httpCode.OK, {data:list}));
    }).catch((err)=>{
        res.send(Object.assign(constants.httpCode.ILLEGAL_PARAM, {data:err}));
    });
}
/**
 * 调用zlmediaKit的 /index/api/openRtpServer接口 ，用于打开一个rtp端口
 */
Media.openRtpServer = function(req){
    const me = this;
    return new Promise(async function(resolve, reject){
        const serverId = req.body.media_server_id;
        const streamId = req.body.stream_id;

        let host =await mediaserverModel.getInfoByServerId(serverId);

        let url = host.zlk_api_host + 'index/api/openRtpServer';
        // 选取一个空余端口号
        let max = host.rtp_max_port;
        let min = host.rtp_min_port;
        if(!me.ports.index) me.ports.index = min-2;

        let port;
        if (me.ports[streamId]) {
            port = me.ports[streamId];
        } else {
            me.ports.index += 2;
            port = me.ports.index;
            me.ports[streamId] = port;
        }
        if (port > max) {
            logger.error(`openRtpServer时， 没有可用端口了 streamId=${streamId}`);
        } else {
            let param = `secret=${host.secret}&port=${port}&enable_tcp=1&stream_id=${streamId}`;

            httpUtils.get(url, param).then((res) => {
                resolve({res: res, mediaIp: host.media_ip});
            }).catch((e) => {
                logger.error(`mediaServierId=${serverId} stream_id=${streamId} 请求媒体服务器 openRtsServer 出错, error=${e}`);
                reject(e);
            });
        }
    });
};

/**
 * 释放所有rtp资源
 */
Media.resetRtpServer=function(serverId){
    Media.listRtpServer(serverId).then(async (list)=>{
        console.info(list);
        for(let i in list.data){
            let stream=list.data[i].stream_id;
            await Media.closeRtpServer(serverId, stream);
        }
    }).catch((err) => {
        logger.error('释放rtp资源出错,检查媒体服务器是否正常。错误信息=', err);
    });
};

/**
 * 调用zlmediaKit的 /index/api/closeRtpServer
 **/
Media.closeRtpServer=async function(serverId, stream){
    let host =await mediaserverModel.getInfoByServerId(serverId);
    console.info('host', host);
    let url = host.zlk_api_host + 'index/api/closeRtpServer';
    let param ="?secret=" + host.secret + "&port=0&enable_tcp=false&stream_id=" + stream;
    httpUtils.get(url, param).then((res)=>{
        logger.log(res);
    }).catch((e)=>{
        logger.error(e);
    });
};

/**
 * 调用zlmediaKit的 /index/api/listRtpServer
 **/
Media.listRtpServer=async function(serverId){
    let host =await mediaserverModel.getInfoByServerId(serverId);

    if(host && host.zlk_api_host){
        let url = host.zlk_api_host + 'index/api/listRtpServer';
        let param ="?secret=" + host.secret;
        return httpUtils.get(url ,param);
    }else{
        logger.error("请打开网页设置媒体服务器地址。");
    }
};
Media.ping=async function(serverId){
    let host =await mediaserverModel.getInfoByServerId(serverId);
    console.log('host',host);
    let url = host.zlk_api_host + 'index/api/listRtpServer';
    let param = "?secret=" + host.secret;
    return httpUtils.get(url, param);
};
/**
 * TODO: 准备换成httpUtils
 * 调用zlmediakit 进行截图操作，暂时不用
 */
Media.snap0=function(query,deviceid,channel){
    return new Promise(function (resolve) {
        let url = constants.zlmedia.url + 'index/api/getSnap';
        let param = "?" + query;
        let path = settingModel.cache.snap_path + "/" + deviceid + "_" + channel + ".jpg";
        request(url + param).pipe(fs.createWriteStream(path));
        resolve({});
    });
};
/**
 * 使用fluent-ffmpeg截图
 */
Media.snap = function(source, deviceid, channel){
    logger.info('snap to' ,settingModel.cache.snap_path , deviceid + "_" + channel + ".jpg", 'source', source);
    return new Promise(function (resolve) {
        ffmpeg({source: source, timeout: 20})
            .on('filenames', function (filenames) {
                let ret = settingModel.cache.snap_path || '';
                let last = ret.charAt(ret.length - 1);
                if (last !== '/') ret = ret + '/';
                let first = ret.charAt(0);
                if (first === '.') ret = ret.substring(1, ret.length);
                if (ret.indexOf('/public') === 0) {
                    ret = ret.replace('/public', '');
                }
                resolve(ret + filenames);
            })
            .on('end', function () {
                logger.log('ffmpeg end');
            })
            .on('stderr', function (stderrLine) {
                logger.log('Stderr output: ' + stderrLine);
            })
            .on('error', function (err) {
                logger.log('Cannot process video: error =', err.message);
            }).addOption(['-rtsp_transport tcp'])
            .screenshots({
                count: 1,
                // timemarks: [ '00:00:02.000' ],
                folder: settingModel.cache.snap_path,
                filename: deviceid + "_" + channel + ".jpg",
                size: '640x?',
                timeout: 20
            });
    });
};

module.exports=Media;
